/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.xuexiang.xui_lib.util;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.Component;

import java.util.ArrayList;

/**
 * 扩展AnimatorProperty以支持多参数values
 *
 * @since 2021-03-29
 */
public class OfAnimatorProperty {
    private static final long NOT_SET_DURATION = -1;
    private static final int PROPERTY_ALPHA = 1;
    private static final int PROPERTY_ROTATE = 2;
    private static final int PROPERTY_SCALE = 3;
    private static final int PROPERTY_MOVE_Y = 4;
    private static final int PROPERTY_MOVE_X = 5;
    private static final int MIN_VALUE_SIZE = 2;

    private final AnimatorGroup animatorGroup = new AnimatorGroup();
    private final ArrayList<AnimatorProperty> animatorArray = new ArrayList<>();
    private final Component target;
    private long duration = NOT_SET_DURATION;
    private int curveType;

    /**
     * 以该组件为目标的构造
     *
     * @param target 动画目标
     */
    public OfAnimatorProperty(Component target) {
        this.target = target;
    }

    /**
     * 设置alpha动画
     *
     * @param values 动画渐进值
     * @return 对象本身
     */
    public OfAnimatorProperty alpha(float... values) {
        genMultiProperty(PROPERTY_ALPHA, values);
        return this;
    }

    /**
     * 设置rotate动画
     *
     * @param values 动画渐进值
     * @return 对象本身
     */
    public OfAnimatorProperty rotate(float... values) {
        check(values);
        for (int i = 0; i < values.length; i++) {
            AnimatorProperty each = new AnimatorProperty(target);
            each.rotate(values[i]);
            animatorArray.add(each);
        }
        return this;
    }

    /**
     * 设置scale动画
     *
     * @param values 动画渐进值
     * @return 对象本身
     */
    public OfAnimatorProperty scale(float... values) {
        genMultiProperty(PROPERTY_SCALE, values);
        return this;
    }

    /**
     * 设置moveY动画
     *
     * @param values 动画渐进值
     * @return 对象本身
     */
    public OfAnimatorProperty moveY(float... values) {
        genMultiProperty(PROPERTY_MOVE_Y, values);
        return this;
    }

    /**
     * 设置moveX动画
     *
     * @param values 动画渐进值
     * @return 对象本身
     */
    public OfAnimatorProperty moveX(float... values) {
        genMultiProperty(PROPERTY_MOVE_X, values);
        return this;
    }

    /**
     * 设置动画插值器
     *
     * @param curveType 动画插值器
     * @return 对象本身
     */
    public OfAnimatorProperty setCurveType(int curveType) {
        this.curveType = curveType;
        return this;
    }

    /**
     * 设置动画时长
     *
     * @param duration 动画时长
     * @return 对象本身
     */
    public OfAnimatorProperty setDuration(long duration) {
        this.duration = duration;
        return this;
    }

    private void genMultiProperty(int propertyType, float... values) {
        check(values);
        for (int i = 1; i < values.length; i++) {
            float from = values[i - 1];
            float to = values[i];
            AnimatorProperty each = new AnimatorProperty(target);
            switch (propertyType) {
                case PROPERTY_ALPHA:
                    each.alphaFrom(from).alpha(to);
                    break;
                case PROPERTY_SCALE:
                    each.scaleXFrom(from).scaleX(to).scaleYFrom(from).scaleY(to);
                    break;
                case PROPERTY_MOVE_X:
                    each.moveFromX(from).moveToX(to);
                    break;
                case PROPERTY_MOVE_Y:
                    each.moveFromY(from).moveToY(to);
                    break;
                default:
                    // NONE
            }
            animatorArray.add(each);
        }
    }

    /**
     * 设置动画状态监听
     *
     * @param listener 状态回调
     * @return 对象本身
     */
    public OfAnimatorProperty setStateChangedListener(Animator.StateChangedListener listener) {
        animatorGroup.setStateChangedListener(listener);
        return this;
    }

    /**
     * 设置循环状态监听
     *
     * @param listener Loop回调
     * @return 对象本身
     */
    public OfAnimatorProperty setLoopedListener(Animator.LoopedListener listener) {
        animatorGroup.setLoopedListener(listener);
        return this;
    }

    /**
     * 开始动画
     */
    public void start() {
        start(true);
    }

    /**
     * 开始动画
     *
     * @param isSerially true:连续, false同时
     * @throws RuntimeException 未设置时长时将提示调用者该异常
     */
    public void start(boolean isSerially) {
        if (duration == NOT_SET_DURATION) {
            throw new RuntimeException("Are you forget to set duration?");
        }
        int size = animatorArray.size();
        for (AnimatorProperty animatorProperty : animatorArray) {
            animatorProperty.setDuration(duration / size)
                .setCurveType(curveType);
        }
        AnimatorProperty[] animatorProperties = animatorArray.toArray(new AnimatorProperty[0]);
        if (isSerially) {
            animatorGroup.runSerially(animatorProperties);
        } else {
            animatorGroup.runParallel(animatorProperties);
        }
        animatorGroup.start();
    }

    private void check(float[] values) {
        if (values == null || values.length < MIN_VALUE_SIZE) {
            throw new IllegalArgumentException("The values args length mast greater than 2!");
        }
    }
}
